package mole 
{
	import mole.entities.CTileMap;
	import mole.entities.obstacles.CObstacle;
	import mole.entities.obstacles.CObstacleConf;
	import mole.entities.obstacles.CObstaclesAssets;
	import net.flashpunk.graphics.Tilemap;
	import net.flashpunk.masks.Grid;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import com.dynamicflash.utils.Base64;
	import flash.errors.EOFError;	
	import flash.events.Event;
	import flash.net.URLLoader;	
	
	/**
	 * ...
	 * @author Cédric Liaudet
	 */
	public class CTemplate 
	{
		[Embed(source = '../data/images/tmw_desert_spacing.png')]
		private static const TILESET_TEST:Class;
		
		public function CTemplate()
		{			
			m_aTilemap = new Array();
			m_Obstacle = new Array();
		}
		
		/**
		 * Callback lorsque le fichier XML est lu.
		 * @param	_Event
		 */
		public function OnXMLLoadedd(xml:XML): void
		{
			// Creation de la tilemap.
			var iWidth:Number = xml.@width;
			var iHeight:Number = xml.@height;
			var iTileWidth:Number = xml.@tilewidth;
			var iTileHeight:Number = xml.@tileheight;
			var iLayer:int = 1000;
			
			CreateGrid(iWidth * iTileWidth, iHeight * iTileHeight, iTileWidth, iTileHeight);
			
			// Chargement des layers.
			for each(var layer:XML in xml.layer)
			{					
				// Vrai si c'est un layer physique.
				var solid:Boolean = false;
				
				// Definie si c'est un decors collisionnable.
				if (layer.properties != null && layer.properties.property.@name == "physic")
				{
					solid = true;					
				}
				
				AddTilemap(TILESET_TEST, layer.data, solid);
			}			
			
			// Chargement des objets.
			for each(var objectgroup:XML in xml.objectgroup)
			{
				var loadFunc:Function = null;
				
				// On définie la méthode a appeler.
				if (objectgroup.@name == "spawn")
				{
					loadFunc = Main.World.OnLoadSpawn;
				}
				else if (objectgroup.@name == "trigger")
				{
					loadFunc = Main.World.OnLoadTrigger;
				}
				else if (objectgroup.@name == "obstacles")
				{
					// On charge les objets du groupe.
					for each(var obstacle:XML in objectgroup.object)
					{
						AddObstacle(obstacle.@name, obstacle.@x, obstacle.@y);
					}
				}
				
				if (loadFunc != null)
				{
					// On charge les objets du groupe.
					for each(var object:XML in objectgroup.object)
					{
						//loadFunc(object.@name, object.@x, object.@y, object.@width, object.@height, object.properties);
					}
				}
				
			}

			Main.World.OnTemplateReady();
		}
		
		public function OnXMLLoaded(_Event:Event): void
		{						
			var XMLLoader:URLLoader = _Event.currentTarget as URLLoader;				
			var xml:XML = XML(XMLLoader.data);
						
			// Creation de la tilemap.
			var iWidth:Number = xml.@width;
			var iHeight:Number = xml.@height;
			var iTileWidth:Number = xml.@tilewidth;
			var iTileHeight:Number = xml.@tileheight;
			var iLayer:int = 1000;
			
			CreateGrid(iWidth * iTileWidth, iHeight * iTileHeight, iTileWidth, iTileHeight);
			
			// Chargement des layers.
			for each(var layer:XML in xml.layer)
			{					
				// Vrai si c'est un layer physique.
				var solid:Boolean = false;
				
				// Definie si c'est un decors collisionnable.
				if (layer.properties != null && layer.properties.property.@name == "physic")
				{
					solid = true;					
				}
				
				AddTilemap(TILESET_TEST, layer.data, solid);
			}			
			
			// Chargement des objets.
			for each(var objectgroup:XML in xml.objectgroup)
			{
				var loadFunc:Function = null;
				
				// On définie la méthode a appeler.
				if (objectgroup.@name == "spawn")
				{
					loadFunc = Main.World.OnLoadSpawn;
				}
				else if (objectgroup.@name == "trigger")
				{
					loadFunc = Main.World.OnLoadTrigger;
				}
				else if (objectgroup.@name == "obstacles")
				{
					// On charge les objets du groupe.
					for each(var obstacle:XML in objectgroup.object)
					{
						AddObstacle(obstacle.@name, obstacle.@x, obstacle.@y);
					}
				}
				
				if (loadFunc != null)
				{
					// On charge les objets du groupe.
					for each(var object:XML in objectgroup.object)
					{
						//loadFunc(object.@name, object.@x, object.@y, object.@width, object.@height, object.properties);
					}
				}
				
			}

			Main.World.OnTemplateReady();
		}		
		
		/**
		 * 
		 * @param	width
		 * @param	height
		 * @param	tileWidth
		 * @param	tileHeight
		 */
		private function CreateGrid(width:uint, height:uint, tileWidth:uint, tileHeight:uint):void
		{
			m_Grid = new Grid(width, height, tileWidth, tileHeight, 0, 0);
		}
		
		
		/**
		 * 
		 * @param	tileset		
		 * @param	_Data Les données a décoder.
		 */
		private function AddTilemap(tileset:*, _Data:XMLList, _bSolid:Boolean) :void
		{
			var tilemap:Tilemap = new Tilemap(tileset, m_Grid.width, m_Grid.height, m_Grid.width / m_Grid.columns, m_Grid.height / m_Grid.rows);			
			
			// Decodage des données
			var mapData:ByteArray = Base64.decodeToByteArray(_Data);
			mapData.endian = Endian.LITTLE_ENDIAN;										

			// On ajoute les tiles.
			for (var row:Number = 0; row < m_Grid.rows; row++)
			{
				for (var col:Number = 0; col < m_Grid.columns; col++)
				{
					try
					{
						var iTile:int = mapData.readInt();
						if (iTile)
						{
							tilemap.setTile(col, row, iTile - 1);
							
							if(_bSolid)
								m_Grid.setCell(col, row, true);
						}
					}
					catch (e:EOFError)
					{
						break;
					}
				}
			}
			
			m_aTilemap.push(tilemap);			
		}
		
		private function AddObstacle(_Name:String, _PosX:Number, _PosY:Number):void
		{
			var obstacle:CObstacleConf = new CObstacleConf();
			obstacle.m_nPosX = _PosX;
			obstacle.m_nPosY = _PosY;
			obstacle.m_Asset = CObstaclesAssets.GetAssetFromName(_Name);
			obstacle.m_nDifficulty = 0;
			
			m_Obstacle.push(obstacle);
		}
		
		/**
		 * Création d'une tilemap.
		 * 
		 */
		public function CreateTilemap(_nPosX:int, _nPosY:int, _bImpossible:Boolean):CTileMap
		{
			var obs:CObstacle = null;
			var aObstacle:Array = new Array;
		/*	if (_bImpossible)
			{
				obs = new CObstacle(0, CObstaclesAssets.GetAssetFromName("impossible"), 3);
				obs.x = _nPosX;
				obs.y = 192;
				Main.World.add(obs);
				aObstacle.push(obs);
			}
			else
			{*/				
				for each(var obstacle:CObstacleConf in m_Obstacle)
				{
					obs = new CObstacle(obstacle.m_nPosX, obstacle.m_Asset, obstacle.m_nDifficulty);
					obs.x = _nPosX + obstacle.m_nPosX;
					obs.y = obstacle.m_nPosY;
					Main.World.add(obs);
					aObstacle.push(obs);
				}			
		//	}
			
			return new CTileMap(m_aTilemap, m_Grid, _nPosX, _nPosY, aObstacle);
		}
		
		private var m_aTilemap:Array; ///< Tableau de représentation graphique d'une carte.
		private var m_Grid:Grid;	  ///< Masque de collision.
		private var m_Obstacle:Array; ///< Tableau d'obstacle.		
	}	
}